pub fn init(nodes: &mut crate::runner::NodeList) {
    internal::sys(nodes);
    internal::debug(nodes);
    internal::bind(nodes);
    internal::if_for(nodes);
    internal::cal(nodes);
    internal::valid(nodes);
    internal::cmd(nodes);
    internal::fs(nodes);
}

pub fn prepare(cli: &mut crate::cli::Config, ctrl: &mut crate::runner::Ctrl) {
    let dir = cli.file.parent().unwrap_or_else(|| {
        crate::error!(
            "Failed to get working dir of  the file {:?}",
            crate::color!(cyan =>  &cli.file)
        );
        crate::exit!("Failed to load scripts");
        panic!();
    });

    ctrl.work_dir = format!("{}", dir.display());

    if false == cli.silent {
        if true == cli.code.is_none() {
            println!(
                "⚡{}⚡ is running for file {} ⚡\n",
                crate::color!(cyan bold blink bright => "FST"),
                crate::color!(cyan bold blink bright =>  cli.file.display())
            );
        } else {
            println!(
                "⚡{}⚡ is running for codes {} ⚡\n",
                crate::color!(cyan bold blink bright => "FST"),
                crate::color!(cyan bold blink bright =>  cli.file.display())
            );
        }
    }

    ctrl.vars.iter_mut().enumerate().for_each(|(line, map)| {
        map.insert("$$LINE".to_string(), (line + 1).into());
    });
}

mod internal {

    use crate::{node::Param, runner::NodeList, Value};

    #[inline]
    pub fn bind(nodes: &mut NodeList) {
        fn b<F>(info: &crate::runner::RunningInfo, ctrl: &mut crate::runner::Ctrl, f: F)
        where
            F: Fn(&crate::runner::RunningInfo, &mut crate::runner::Ctrl, &String, &Value),
        {
            let key = info.token_params.get(0);
            let val = info.caller_params.get(1);

            match (key, val) {
                (Some(&Param::Var(ref key)), Some(val)) => {
                    if val.is_valid() {
                        f(info, ctrl, key, val);
                    } else {
                        crate::error!(
                            "Can not bind value as {:?} {}",
                            crate::color!(cyan => val),
                            info.line()
                        );

                        crate::tip!(
                            "The value {:?} may be forget to be bound.",
                            crate::color!(cyan => val)
                        );

                        info.cli.may_exit();
                    }
                }

                (None, _) => {
                    crate::error!(
                        "Can not bind key as {:?} {}",
                        crate::color!(cyan => key),
                        info.line()
                    );
                    crate::tip!(
                        "Is it key {:?} a constant type?",
                        crate::color!(cyan => key)
                    );
                    crate::tip!(
                        "It is guaranteed that bind Value {:?} is valid.",
                        crate::color!(cyan => val)
                    );

                    info.cli.may_exit();
                }

                (_, None) => {
                    crate::error!(
                        "Can not bind value as {:?} {}",
                        crate::color!(cyan => val),
                        info.line()
                    );
                    crate::tip!(
                        "The value {:?} may be forget to be bound.",
                        crate::color!(cyan => val)
                    );

                    info.cli.may_exit();
                }
                _ => {
                    crate::error!(
                        "Unknown error happened when using {} {}",
                        crate::color!(cyan => info.caller),
                        info.line()
                    );

                    if info.cli.debug {
                        crate::debug!(
                            "BIND {} = {:?}",
                            crate::color!(cyan => "KEY"),
                            crate::color!(cyan => key)
                        );
                        crate::debug!(
                            "BIND {} = {:?}",
                            crate::color!(cyan => "VAL"),
                            crate::color!(cyan => val)
                        );
                    }

                    info.cli.may_exit();
                }
            }
        }

        nodes.provide("@Bind", |info, ctrl| {
            b(&info, ctrl, |info, ctrl, key, val| {
                ctrl.set(key, val, &info);
            });
        });

        nodes.provide("@BindRoot", |info, ctrl| {
            b(&info, ctrl, |_, ctrl, key, val| {
                ctrl.vars[0].insert(key.to_string(), val.clone().into());
            });
        });

        nodes.provide("@BindAll", |info, ctrl| {
            b(&info, ctrl, |_, ctrl, key, val| {
                for i in 0..ctrl.vars.len() {
                    ctrl.vars[i].insert(key.to_string(), val.clone().into());
                }
            });
        });
    }

    #[inline]
    pub fn sys(nodes: &mut NodeList) {
        nodes.provide("@App", |info, ctrl| {
            ctrl.set("$.VERSION", "v0.2.0", &info);
            ctrl.set("$.ANTHOR", "shawroger", &info);
        });

        nodes.provide("@Exit", |info, _| {
            crate::exit!("process exit {}", info.line())
        });

        nodes.provide("@Token", |info, ctrl| match info.caller_params.get(0) {
            Some(v) => {
                let value = ctrl.seek(&v.into(), &info);
                ctrl.set("$.token", value, &info);
            }

            _ => {
                crate::error!("Missing token params {}", info.line());
            }
        });

        nodes.provide("@Input", |info, ctrl| {
            for (i, arg) in info.cli.args.iter().enumerate() {
                ctrl.set(format!("$.input.{}", i), arg.as_str(), &info);
            }
        });

        nodes.provide("@Parse", |info, ctrl| match info.caller_params.get(0) {
            Some(v) => {
                if v.is_valid() {
                    match Value::parse(v.display().as_str()) {
                        Value::String(v) => {
                            ctrl.set("$.res", v, &info);
                            ctrl.set("$.is.str", 1, &info);
                            ctrl.set("$.is.float", 0, &info);
                            ctrl.set("$.is.int", 0, &info);
                            ctrl.set("$.is.token", 0, &info);
                        }
                        Value::Float(v) => {
                            ctrl.set("$.res", v, &info);
                            ctrl.set("$.is.float", 1, &info);
                            ctrl.set("$.is.str", 0, &info);
                            ctrl.set("$.is.int", 0, &info);
                            ctrl.set("$.is.token", 0, &info);
                        }
                        Value::Int(v) => {
                            ctrl.set("$.res", v, &info);
                            ctrl.set("$.is.int", 1, &info);
                            ctrl.set("$.is.str", 0, &info);
                            ctrl.set("$.is.float", 0, &info);
                            ctrl.set("$.is.token", 0, &info);
                        }
                        Value::Token(v) => {
                            ctrl.set("$.res", v, &info);
                            ctrl.set("$.is.token", 1, &info);
                            ctrl.set("$.is.int", 0, &info);
                            ctrl.set("$.is.str", 0, &info);
                            ctrl.set("$.is.float", 0, &info);
                        }
                    }
                } else {
                    crate::error!(
                        "Unexpected {} values {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => v),
                        info.line()
                    );
                }
            }

            None => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });

        nodes.provide("@Env", |info, ctrl| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                if let Ok(s) = std::env::var(s) {
                    ctrl.set("$.env", s, &info);
                } else {
                    crate::error!(
                        "Value {} is not found as {} keys {}",
                        crate::color!(cyan => s),
                        crate::color!(cyan => info.caller),
                        info.line()
                    );
                }
            }
            Some(v) => {
                crate::error!(
                    "Value {:?} is invalid as {} keys {}",
                    crate::color!(cyan => v),
                    crate::color!(cyan => info.caller),
                    info.line()
                );
            }

            None => {
                crate::error!(
                    "{} value is invalid as {} keys {}",
                    crate::color!(cyan => "Empty"),
                    crate::color!(cyan => info.caller),
                    info.line()
                );
            }
        });

        #[allow(deprecated)]
        nodes.provide("@Date", |info, ctrl| {
            let date = time::Date::today();

            let year = format!("{}", date.year());

            let mut month = format!("{}", date.month());

            let mut day = format!("{}", date.day());

            if date.month() < 10 {
                month = format!("0{}", date.month());
            }

            if date.day() < 10 {
                day = format!("0{}", date.day());
            }

            ctrl.set("$.DATE", format!("{}-{}-{}", year, month, day), &info);
            ctrl.set("$.YEAR", year, &info);
            ctrl.set("$.MONTH", month, &info);
            ctrl.set("$.DAY", day, &info);
        });

        #[allow(deprecated)]
        nodes.provide("@Time", |info, ctrl| {
            let time = time::Time::now();

            let mut hour = format!("{}", time.hour());
            if time.hour() < 10 {
                hour = format!("0{}", time.hour());
            }

            let mut minute = format!("{}", time.minute());
            if time.minute() < 10 {
                minute = format!("0{}", time.minute());
            }

            let mut second = format!("{}", time.second());
            if time.second() < 10 {
                second = format!("0{}", time.second());
            }

            if let Some(offset) = info.caller_params.get(0) {
                match offset {
                    Value::Int(n) => {
                        let true_hour = time.hour() + *n as u8;
                        hour = format!("{}", true_hour);
                        if true_hour < 10 {
                            hour = format!("0{}", true_hour);
                        }
                    }
                    _ => {}
                }
            }
            ctrl.set("$.TIME", format!("{}:{}:{}", hour, minute, second), &info);
            ctrl.set("$.HOUR", hour, &info);
            ctrl.set("$.MINUTE", minute, &info);
            ctrl.set("$.SECOND", second, &info);
        });

        nodes.provide("@Println", |info, _| {
            info.caller_params.iter().for_each(|v| {
                if v.is_valid() {
                    if info.cli.debug {
                        crate::debug!(
                            "{:?} {:>10} {}",
                            v,
                            crate::color!(cyan => info.caller),
                            info.line(),
                        );
                    } else {
                        let disp = v.display();
                        if disp.eq("\n") || disp.eq("\r\n") || disp.eq("\\n") || disp.eq("\\r\\n") {
                            println!("");
                        } else {
                            println!("{}", disp);
                        }
                    }
                } else {
                    crate::error!(
                        "Value {:?} is not for {} {}",
                        crate::color!(cyan => v),
                        crate::color!(cyan => info.caller),
                        info.line()
                    );
                }
            });
        });

        nodes.provide("@Print", |info, _| {
            info.caller_params.iter().for_each(|v| {
                if v.is_valid() {
                    if info.cli.debug {
                        crate::debug!(
                            "{:?} {:>10} {}",
                            v,
                            crate::color!(cyan => info.caller),
                            info.line(),
                        );
                    } else {
                        let disp = v.display();

                        if disp.eq("\n") || disp.eq("\r\n") || disp.eq("\\n") || disp.eq("\\r\\n") {
                            println!("");
                        } else {
                            print!("{}", disp);
                        }
                    }
                } else {
                    crate::error!(
                        "Value {:?} is not for {} {}",
                        crate::color!(cyan => v),
                        crate::color!(cyan => info.caller),
                        info.line()
                    );
                }
            });
        });
    }

    #[inline]
    pub fn debug(nodes: &mut NodeList) {
        nodes.provide("@DebugExec", |_, ctrl| {
            crate::debug!("print global executive list");

            println!(
                "{}",
                crate::color!(blink bright => "-".repeat(6 + "print global executive list".len()))
            );

            ctrl.execlist.iter().enumerate().for_each(|(i, v)| {
                println!(
                    "{:<3} {:3} {:?}",
                    crate::color!(green => i+1),
                    crate::color!(blink => ":"),
                    crate::color!(cyan => v),
                );
            });

            println!("");
        });

        nodes.provide("@DebugLoop", |_, ctrl| {
        crate::debug!("print global loop running list");

        println!(
            "{}",
            crate::color!(blink bright => "-".repeat(6 + "print global loop running list".len())),
        );

        ctrl.looplist.iter().enumerate().for_each(|(i, v)| {
            println!(
                "{:<3} {:3} {:?}",
                crate::color!(green => i+1),
                crate::color!(blink => ":"),
                crate::color!(cyan => v),
            );
        });

        println!("");
    });

        nodes.provide("@DebugCaller", |info, _| {
            crate::debug!("show all valid callers {}", info.line());
            println!(
                "{}",
                crate::color!(blink bright => "-".repeat(29 + info.line_len())),
            );

            let mut caller_list = info
                .nodelist
                .callers
                .iter()
                .map(|(s, _)| s)
                .collect::<Vec<&String>>();

            caller_list.sort();

            caller_list.iter().enumerate().for_each(|(i, name)| {
                println!(
                    "{:<4} =>  {}",
                    crate::color!(green blink => i+1),
                    crate::color!(cyan bold => name),
                );
            });

            println!("");
        });

        nodes.provide("@DebugVars", |info, ctrl| {
        match info.caller_params.get_valid(0) {
            Some(v) => {
                crate::debug!("{} {}", v.display(), info.line());

                println!(
                    "{}", crate::color!(blink bright => "-".repeat(v.display().len() + 7 + info.line_len())),
                );
            }
            None => {
                crate::debug!("{}", info.line());

                println!(
                    "{}", crate::color!(blink bright => "-".repeat(6 + info.line_len())),
                );
            }
        }

        let vars = &ctrl.vars[info.nodelist.parents[info.node.line]];
        let mut keys = vars.keys().collect::<Vec<&String>>();

        keys.sort();

        for k in keys {
            if let Some(v) = vars.get(k) {
                println!(
                    "{:3} {:1} {:?}",
                    crate::color!(green => k),
                    crate::color!(blink => ":"),
                    crate::color!(cyan => v),
                );
            }
        }

        println!("");
    });

        nodes.provide("@Debug", |info, ctrl| {
            crate::debug!("globally {}", info.line());

            println!(
                "{0}\n{0}\n",
                crate::color!(blink bright => ".".repeat(16 + info.line_len())),
            );

            ctrl.vars.iter().enumerate().for_each(|(index, map)| {
                crate::debug!("at line {}", index + 1);
                println!(
                    "{}",
                    crate::color!(blink bright => "-".repeat(6 + info.line_len())),
                );

                map.iter().for_each(|(k, v)| {
                    println!(
                        "{:3} {:1} {:?}",
                        crate::color!(green => k),
                        crate::color!(blink => ":"),
                        crate::color!(cyan => v),
                    );
                });

                println!("");
            })
        });
    }

    #[inline]
    pub fn if_for(nodes: &mut NodeList) {
        nodes.provide("@For", |info, ctrl| {
            match info.caller_params.get_valid(0) {
                Some(&Value::Int(value)) if value > 0 => {
                    let line = info.node.line;
                    let value = value as usize;
                    // 第一次循环
                    if ctrl.looplist[line].2 != line {
                        // 设置起始值
                        ctrl.looplist[line] = (value, 0, line);
                        info.nodelist.children[line]
                            .iter()
                            .for_each(|&i| ctrl.looplist[i] = ctrl.looplist[line]);
                    } else {
                        // 否则叠加循环次数
                        ctrl.looplist[line].1 = ctrl.looplist[line].1 + 1;
                        info.nodelist.children[line]
                            .iter()
                            .for_each(|&i| ctrl.looplist[i] = ctrl.looplist[line]);
                    }

                    ctrl.set_scope("$.index", ctrl.looplist[info.node.line].1, &info);
                    ctrl.set_scope("$.uindex", 1 + ctrl.looplist[info.node.line].1, &info);
                }

                Some(&Value::Int(value)) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value),
                        info.line()
                    );

                    crate::why!(
                        "params {:?} is int type but it is < 0 🤕",
                        crate::color!(red => value)
                    );

                    crate::tip!(
                        "Change param as {:?} then it will work 💡",
                        crate::color!(red => -1 * value)
                    );

                    info.cli.may_exit();
                }

                Some(&Value::Float(value)) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value),
                        info.line()
                    );

                    crate::why!("params {:?} is float type 🤕", crate::color!(red => value));

                    crate::tip!(
                        "Change param as {:?} then it will work 💡",
                        crate::color!(red =>  (value as i64).abs())
                    );

                    info.cli.may_exit();
                }

                Some(value) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value.display()),
                        info.line()
                    );

                    crate::why!(
                        "params {:?} is not unsigned int type 🤕",
                        crate::color!(red => value.display())
                    );

                    crate::tip!("params should be unsigned int type 💡");

                    info.cli.may_exit();
                }

                None => {
                    crate::error!(
                        "Missing {} params {}",
                        crate::color!(cyan => info.caller),
                        info.line()
                    );

                    crate::why!("params is missing 🤕");
                    crate::tip!("params should be unsigned int type 💡");

                    info.cli.may_exit();
                }
            }
        });

        nodes.provide("@If", |info, ctrl| {
            let line = info.node.line;
            match info.caller_params.get(0) {
                Some(&Value::Int(x)) if x <= 0 => {
                    // 子节点也为 false
                    info.nodelist.children[line]
                        .iter()
                        .for_each(|&i| ctrl.execlist[i] = false);
                    ctrl.ptr += 1;
                    return;
                }
                Some(&Value::Int(x)) if x > 0 => {
                    info.nodelist.children[line]
                        .iter()
                        .for_each(|&i| ctrl.execlist[i] = true);
                    ctrl.ptr += 1;
                    return;
                }

                Some(&Value::Float(value)) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value),
                        info.line()
                    );

                    crate::why!("params {:?} is float type 🤕", crate::color!(red => value));

                    crate::tip!(
                        "Change param as {:?} then it will work 💡",
                        crate::color!(red =>  (value as i64).abs())
                    );

                    info.cli.may_exit();
                }

                Some(value) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value.display()),
                        info.line()
                    );

                    crate::why!(
                        "params {:?} is not int type 🤕",
                        crate::color!(red => value.display())
                    );

                    crate::tip!("params should be int type 💡");
                    crate::tip!("params > 0 means {}", crate::color!(cyan => "true"));
                    crate::tip!("params <= 0 means {}", crate::color!(cyan => "false"));

                    info.cli.may_exit();
                }

                None => {
                    crate::error!(
                        "Missing {} params {}",
                        crate::color!(cyan => info.caller),
                        info.line()
                    );

                    crate::why!("params is missing 🤕");
                    crate::tip!("params should be int type 💡");
                    crate::tip!("params > 0 means {}", crate::color!(cyan => "true"));
                    crate::tip!("params <= 0 means {}", crate::color!(cyan => "false"));

                    info.cli.may_exit();
                }
            }
        });

        nodes.provide("@Not", |info, ctrl| {
            let line = info.node.line;
            match info.caller_params.get(0) {
                Some(&Value::Int(x)) if x > 0 => {
                    // 子节点也为 false
                    info.nodelist.children[line]
                        .iter()
                        .for_each(|&i| ctrl.execlist[i] = false);
                    ctrl.ptr += 1;
                    return;
                }
                Some(&Value::Int(x)) if x <= 0 => {
                    info.nodelist.children[line]
                        .iter()
                        .for_each(|&i| ctrl.execlist[i] = true);
                    ctrl.ptr += 1;
                    return;
                }

                Some(&Value::Float(value)) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value),
                        info.line()
                    );

                    crate::why!("params {:?} is float type 🤕", crate::color!(red => value));

                    crate::tip!(
                        "Change param as {:?} then it will work 💡",
                        crate::color!(red =>  (value as i64).abs())
                    );

                    info.cli.may_exit();
                }

                Some(value) => {
                    crate::error!(
                        "Invalid {} params {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => value.display()),
                        info.line()
                    );

                    crate::why!(
                        "params {:?} is not int type 🤕",
                        crate::color!(red => value.display())
                    );

                    crate::tip!("params should be int type 💡");
                    crate::tip!("params > 0 means {}", crate::color!(cyan => "true"));
                    crate::tip!("params <= 0 means {}", crate::color!(cyan => "false"));

                    info.cli.may_exit();
                }

                None => {
                    crate::error!(
                        "Missing {} params {}",
                        crate::color!(cyan => info.caller),
                        info.line()
                    );

                    crate::why!("params is missing 🤕");
                    crate::tip!("params should be int type 💡");
                    crate::tip!("params > 0 means {}", crate::color!(cyan => "true"));
                    crate::tip!("params <= 0 means {}", crate::color!(cyan => "false"));

                    info.cli.may_exit();
                }
            }
        });

        nodes.provide("@Ingore", |info, ctrl| {
            let line = info.node.line;
            ctrl.execlist[line] = false;
            info.nodelist.children[line]
                .iter()
                .for_each(|&i| ctrl.execlist[i] = false);

            ctrl.ptr += 1;
        });
    }

    #[inline]
    pub fn cal(nodes: &mut NodeList) {
        nodes.provide("@Equal", |info, ctrl| {
            let (a, b) = (info.caller_params.get(0), info.caller_params.get(1));
            match (a, b) {
                (Some(Value::String(a)), Some(Value::String(b))) => {
                    if a == b {
                        ctrl.set("$.true", 1, &info);
                        ctrl.set("$.false", 0, &info);
                        ctrl.set("$.ok", 1, &info);
                    } else {
                        ctrl.set("$.true", 0, &info);
                        ctrl.set("$.false", 1, &info);
                        ctrl.set("$.ok", 1, &info);
                    }
                }

                (Some(Value::Int(a)), Some(Value::Int(b))) => {
                    if a == b {
                        ctrl.set("$.true", 1, &info);
                        ctrl.set("$.false", 0, &info);
                        ctrl.set("$.ok", 1, &info);
                    } else {
                        ctrl.set("$.true", 0, &info);
                        ctrl.set("$.false", 1, &info);
                        ctrl.set("$.ok", 1, &info);
                    }
                }

                (Some(Value::Float(a)), Some(Value::Float(b))) => {
                    if a == b {
                        ctrl.set("$.true", 1, &info);
                        ctrl.set("$.false", 0, &info);
                        ctrl.set("$.ok", 1, &info);
                    } else {
                        ctrl.set("$.true", 0, &info);
                        ctrl.set("$.false", 1, &info);
                        ctrl.set("$.ok", 1, &info);
                    }
                }

                (Some(Value::Int(a)), Some(Value::Float(b))) => {
                    if (*a as f64).eq(b) {
                        ctrl.set("$.true", 1, &info);
                        ctrl.set("$.false", 0, &info);

                        ctrl.set("$.ok", 1, &info);
                    } else {
                        ctrl.set("$.true", 0, &info);
                        ctrl.set("$.false", 1, &info);

                        ctrl.set("$.ok", 1, &info);
                    }
                }

                (Some(Value::Float(a)), Some(Value::Int(b))) => {
                    if (*b as f64).eq(a) {
                        ctrl.set("$.true", 1, &info);
                        ctrl.set("$.false", 0, &info);

                        ctrl.set("$.ok", 1, &info);
                    } else {
                        ctrl.set("$.true", 0, &info);
                        ctrl.set("$.false", 1, &info);

                        ctrl.set("$.ok", 1, &info);
                    }
                }
                _ => {
                    ctrl.set("$.true", 0, &info);
                    ctrl.set("$.false", 0, &info);
                    ctrl.set("$.ok", 0, &info);
                    crate::error!(
                        "Unexpected {} values {:?} and {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => a),
                        crate::color!(red => b),
                        info.line()
                    );
                }
            }
        });

        nodes.provide("@Contain", |info, ctrl| {
            let (a, b) = (info.caller_params.get(0), info.caller_params.get(1));
            match (a, b) {
                (Some(Value::String(a)), Some(Value::String(b))) => {
                    if a.contains(b) {
                        ctrl.set("$.true", 1, &info);
                        ctrl.set("$.false", 0, &info);
                        ctrl.set("$.ok", 1, &info);
                    } else {
                        ctrl.set("$.true", 0, &info);
                        ctrl.set("$.false", 1, &info);
                        ctrl.set("$.ok", 1, &info);
                    }
                }
                _ => {
                    ctrl.set("$.true", 0, &info);
                    ctrl.set("$.false", 0, &info);
                    ctrl.set("$.ok", 0, &info);
                    crate::error!(
                        "Unexpected {} values {:?} and {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => a),
                        crate::color!(red => b),
                        info.line()
                    );
                }
            }
        });

        nodes.provide("@Add", |info, ctrl| {
            let mut res = 0.0;
            info.caller_params.iter().for_each(|param| match param {
                Value::Float(v) => res = res + v,
                Value::Int(v) => res = res + *v as f64,
                _ => {
                    crate::error!(
                        "Unexpected {} values {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => param),
                        info.line()
                    );
                }
            });

            if res.floor().eq(&res) {
                ctrl.set("$.res", res as i64, &info);
            } else {
                ctrl.set("$.res", res, &info);
            }
        });

        nodes.provide("@Mul", |info, ctrl| {
            let mut res = 1.0;
            info.caller_params.iter().for_each(|param| match param {
                Value::Float(v) => res = res * v,
                Value::Int(v) => res = res * *v as f64,
                _ => {
                    crate::error!(
                        "Unexpected {} values {:?} and {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => param),
                        info.line()
                    );
                }
            });

            if res.floor().eq(&res) {
                ctrl.set("$.res", res as i64, &info);
            } else {
                ctrl.set("$.res", res, &info);
            }
        });

        nodes.provide("@Sub", |info, ctrl| {
            let mut res = 0.0;
            info.caller_params
                .iter()
                .enumerate()
                .for_each(|(i, param)| match param {
                    Value::Int(v) => {
                        if i == 0 {
                            res = *v as f64
                        } else {
                            res = res - *v as f64
                        }
                    }
                    Value::Float(v) => {
                        if i == 0 {
                            res = *v as f64
                        } else {
                            res = res - *v as f64
                        }
                    }
                    _ => {
                        crate::error!(
                            "Unexpected {} values {:?} {}",
                            crate::color!(cyan => info.caller),
                            crate::color!(red => param),
                            info.line()
                        );
                    }
                });

            if res.floor().eq(&res) {
                ctrl.set("$.res", res as i64, &info);
            } else {
                ctrl.set("$.res", res, &info);
            }
        });

        nodes.provide("@Div", |info, ctrl| {
            let mut res = 1.0f64;
            info.caller_params
                .iter()
                .enumerate()
                .for_each(|(i, param)| match param {
                    Value::Int(v) => {
                        if i == 0 {
                            res = *v as f64
                        } else {
                            res = res / *v as f64
                        }
                    }
                    Value::Float(v) => {
                        if i == 0 {
                            res = *v
                        } else {
                            res = res / *v
                        }
                    }
                    _ => {
                        crate::error!(
                            "Unexpected {} values {:?} {}",
                            crate::color!(cyan => info.caller),
                            crate::color!(red => param),
                            info.line()
                        );
                    }
                });

            if res.floor().eq(&res) {
                ctrl.set("$.res", res as i64, &info);
            } else {
                ctrl.set("$.res", res, &info);
            }
        });

        nodes.provide("@Join", |info, ctrl| {
            let mut res = String::new();
            info.caller_params.iter().for_each(|param| {
                if param.is_valid() {
                    res.push_str(param.display().as_str());
                } else {
                    crate::error!(
                        "Unexpected {} values {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => param),
                        info.line()
                    );
                }
            });

            ctrl.set("$.res", res, &info);
        });
    }

    #[inline]
    pub fn valid(nodes: &mut NodeList) {
        nodes.provide("@Valid", |info, ctrl| {
            for param in info.caller_params.iter() {
                if false == param.is_valid() {
                    ctrl.set("$.true", 0, &info);
                    ctrl.set("$.false", 1, &info);
                    return;
                }
            }

            ctrl.set("$.true", 1, &info);
            ctrl.set("$.false", 0, &info);
        });

        nodes.provide("@Invalid", |info, ctrl| {
            for param in info.caller_params.iter() {
                if true == param.is_valid() {
                    ctrl.set("$.true", 0, &info);
                    ctrl.set("$.false", 1, &info);
                    return;
                }
            }

            ctrl.set("$.true", 1, &info);
            ctrl.set("$.false", 0, &info);
        });
    }

    #[inline]
    pub fn cmd(nodes: &mut NodeList) {
        nodes.provide("@Command", |info, ctrl| {
            let vars = &ctrl.vars[info.nodelist.parents[info.node.line]];

            match info.caller_params.get(0) {
                Some(Value::String(s)) => {
                    let list = s
                        .split(" ")
                        .filter(|s| s.len() > 0)
                        .map(|arg| {
                            if arg.starts_with("$") && vars.get(arg).is_some() {
                                vars.get(arg)
                                    .unwrap_or_else(|| {
                                        crate::error!(
                                            "Unexpected {} values {:?} {}",
                                            crate::color!(cyan => info.caller),
                                            crate::color!(red => &arg),
                                            info.line()
                                        );
                                        crate::exit!("Crashed when running invalid command");
                                        panic!();
                                    })
                                    .display()
                            } else {
                                arg.to_string()
                            }
                        })
                        .collect::<Vec<String>>();

                    let cmd = list.join(" ");
                    let mut command = if list.len() > 0 {
                        std::process::Command::new(&list[0])
                    } else {
                        std::process::Command::new(&cmd)
                    };

                    if list.len() > 1 {
                        for arg in &list[1..] {
                            command.arg(arg);
                        }
                    }

                    if false == info.cli.silent {
                        println!(
                            "{} {} 🔋 {}",
                            crate::color!(cyan blink bright bold => "CMD"),
                            crate::color!(yellow bold => &cmd),
                            info.line()
                        );
                        println!("{}", "-".repeat(8 + cmd.len() + info.line_len()));
                    }

                    let output = command.output().unwrap_or_else(|e| {
                        crate::error!("Failed to generate command output {}", info.line());
                        crate::why!("Error happened as {:?}", crate::color!(red => e));
                        crate::exit!("Crashed when resolving the output of command");
                        panic!();
                    });

                    println!(
                        "{}",
                        String::from_utf8(output.stdout).unwrap_or_else(|_| {
                            crate::error!(
                                "Failed to transform stdout of command output into UFT8 {}",
                                info.line()
                            );
                            crate::exit!("Crashed when printing the stdout of command");
                            panic!();
                        })
                    );
                }
                Some(v) => {
                    crate::error!(
                        "Unexpected {} values {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => v),
                        info.line()
                    );
                    crate::exit!("Crashed when running invalid command");
                    panic!();
                }

                _ => {
                    crate::error!(
                        "Unexpected {} values {} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => "None"),
                        info.line()
                    );
                    crate::exit!("Crashed when running invalid command");
                    panic!();
                }
            }
        });
    }

    #[inline]
    pub fn fs(nodes: &mut NodeList) {
        nodes.provide("@Stat", |info, ctrl| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                let path = std::path::Path::new(s);

                if false == path.exists() {
                    ctrl.set("$.valid", 1, &info);
                    ctrl.set("$.exist", 0, &info);
                    ctrl.set("$.file", 0, &info);
                    ctrl.set("$.dir", 0, &info);
                    return;
                }

                if path.is_dir() {
                    ctrl.set("$.valid", 1, &info);
                    ctrl.set("$.exist", 1, &info);
                    ctrl.set("$.file", 0, &info);
                    ctrl.set("$.dir", 1, &info);
                    return;
                }

                if path.is_file() {
                    ctrl.set("$.valid", 1, &info);
                    ctrl.set("$.exist", 1, &info);
                    ctrl.set("$.file", 1, &info);
                    ctrl.set("$.dir", 0, &info);
                    return;
                }
            }

            _ => {
                ctrl.set("$.valid", 0, &info);
                ctrl.set("$.exist", 0, &info);
                ctrl.set("$.file", 0, &info);
                ctrl.set("$.dir", 0, &info);
            }
        });
        nodes.provide("@Read", |info, ctrl| match info.caller_params.get(0) {
            Some(Value::String(s)) => match std::fs::read_to_string(&s) {
                Ok(s) => {
                    ctrl.set("$.content", s, &info);
                }
                Err(_) => {
                    crate::error!(
                        "File {} is not found {}",
                        crate::color!(cyan => s),
                        info.line()
                    );
                    crate::tip!("Try to check the path of the file");
                    crate::exit!("Failed to load inline file");
                    ctrl.set("", s.as_str(), &info);
                }
            },
            Some(param) => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => param),
                    info.line()
                );
            }
            None => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });

        nodes.provide("@Entry", |info, ctrl| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                let dir = relative_path::RelativePath::new(&ctrl.work_dir)
                    .join_normalized(&s)
                    .normalize();

                let list = glob::glob(dir.to_string().as_str())
                    .unwrap_or_else(|_| {
                        crate::error!(
                            "Entry path {} is not found {}",
                            crate::color!(cyan => s),
                            info.line()
                        );
                        crate::tip!("Try to check the path of the file");
                        crate::exit!("Failed to load inline entry path");
                        panic!();
                    })
                    .map(|entry| {
                        entry.unwrap_or_else(|e| {
                            crate::error!(
                                "Unexpected {} error {:?} {}",
                                crate::color!(cyan => info.caller),
                                crate::color!(red => e),
                                info.line()
                            );

                            panic!();
                        })
                    })
                    .collect::<Vec<std::path::PathBuf>>();

                let value = list.len();
                let line = info.node.line;

                // 第一次循环
                if ctrl.looplist[line].2 != line {
                    // 设置起始值
                    ctrl.looplist[line] = (value, 0, line);
                    info.nodelist.children[line]
                        .iter()
                        .for_each(|&i| ctrl.looplist[i] = ctrl.looplist[line]);
                } else {
                    // 否则叠加循环次数
                    ctrl.looplist[line].1 = ctrl.looplist[line].1 + 1;
                    info.nodelist.children[line]
                        .iter()
                        .for_each(|&i| ctrl.looplist[i] = ctrl.looplist[line]);
                }

                if false == list.is_empty() {
                    let i = ctrl.looplist[info.node.line].1;
                    let ext = &list[i]
                        .extension()
                        .map(|s| s.to_str())
                        .flatten()
                        .unwrap_or("");

                    let name = &list[i]
                        .file_name()
                        .map(|s| s.to_str())
                        .flatten()
                        .unwrap_or("");

                    ctrl.set_scope("$.index", i, &info);
                    ctrl.set_scope("$.uindex", 1 + i, &info);
                    ctrl.set_scope("$.entry", &list[i], &info);
                    ctrl.set_scope("$.ext", *ext, &info);
                    ctrl.set_scope("$.name", *name, &info);
                }
            }

            Some(param) => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => param),
                    info.line()
                );
            }
            _ => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });

        nodes.provide("@Remove", |info, _| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                glob::glob(s)
                    .unwrap_or_else(|_| {
                        crate::error!(
                            "Remove path {} is not found {}",
                            crate::color!(cyan => s),
                            info.line()
                        );
                        crate::tip!("Try to check the path of the file");
                        crate::exit!("Failed to load inline remove path");
                        panic!();
                    })
                    .map(|entry| {
                        entry.unwrap_or_else(|e| {
                            crate::error!(
                                "Unexpected {} error {:?} {}",
                                crate::color!(cyan => info.caller),
                                crate::color!(red => e),
                                info.line()
                            );

                            crate::exit!("Crashed at {}", crate::color!(cyan => "entry::unwrap"));

                            panic!();
                        })
                    })
                    .for_each(|e| {
                        if let Err(_) = std::fs::remove_file(&e) {
                            std::fs::remove_dir_all(&e).unwrap_or_else(|e| {
                                crate::error!(
                                    "Unexpected {} path error {:?} {}",
                                    crate::color!(cyan => info.caller),
                                    crate::color!(red => e),
                                    info.line()
                                );

                                crate::exit!(
                                    "Crashed at {}",
                                    crate::color!(cyan => "std::fs::remove_file")
                                );
                                panic!();
                            })
                        }
                    });
            }

            Some(param) => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => param),
                    info.line()
                );
            }
            _ => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });

        nodes.provide("@CreateDir", |info, _| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                if std::path::Path::new(&s).exists() {
                    crate::exit!(
                        "Path {} is already existed {}",
                        crate::color!(cyan => s),
                        info.line()
                    )
                }

                std::fs::create_dir(&s).unwrap_or_else(|e| {
                    crate::error!(
                        "Unexpected {} path error {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => e),
                        info.line()
                    );

                    crate::exit!("Crashed when creating dir {}", crate::color!(cyan => s));

                    panic!();
                });
            }

            Some(param) => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => param),
                    info.line()
                );
            }
            _ => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });

        nodes.provide("@CreateFile", |info, _| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                if std::path::Path::new(&s).exists() {
                    crate::exit!(
                        "Path {} is already existed {}",
                        crate::color!(cyan => s),
                        info.line()
                    )
                }

                std::fs::File::create(&s).unwrap_or_else(|e| {
                    crate::error!(
                        "Unexpected {} path error {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => e),
                        info.line()
                    );

                    crate::exit!("Crashed when creating file {}", crate::color!(cyan => s));

                    panic!();
                });
            }

            Some(param) => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => param),
                    info.line()
                );
            }
            _ => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });

        nodes.provide("@Write", |info, _| {
            use std::io::Write;
            let (path, content) = (info.caller_params.get(0), info.caller_params.get(1));

            match (path, content) {
                (Some(Value::String(s)), Some(content)) => {
                    let mut handler = std::fs::OpenOptions::new()
                        .append(true)
                        .open(s)
                        .unwrap_or_else(|e| {
                            crate::exit!(
                                "Path {} failed to open for {:?} {}",
                                crate::color!(cyan => s),
                                crate::color!(red => e),
                                info.line()
                            );

                            panic!();
                        });

                    handler
                        .write_all(content.display().as_bytes())
                        .unwrap_or_else(|e| {
                            crate::exit!(
                                "Path {} failed to write for {:?} {}",
                                crate::color!(cyan => s),
                                crate::color!(red => e),
                                info.line()
                            );

                            panic!();
                        });
                }

                (Some(Value::String(s)), _) => {
                    let mut handler = std::fs::File::create(s).unwrap_or_else(|e| {
                        crate::exit!(
                            "Path {} failed to open for {:?} {}",
                            crate::color!(cyan => s),
                            crate::color!(red => e),
                            info.line()
                        );

                        panic!();
                    });

                    handler.write_all("".as_bytes()).unwrap_or_else(|e| {
                        crate::exit!(
                            "Path {} failed to clear for {:?} {}",
                            crate::color!(cyan => s),
                            crate::color!(red => e),
                            info.line()
                        );

                        panic!();
                    });
                }

                (Some(v), _) => {
                    crate::error!(
                        "Unexpected {} values {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(red => v),
                        info.line()
                    );
                }
                _ => {
                    crate::error!(
                        "Unexpected {} values {:?} {:?} {}",
                        crate::color!(cyan => info.caller),
                        crate::color!(cyan => path),
                        crate::color!(red => content),
                        info.line()
                    );
                }
            }
        });

        nodes.provide("@Lines", |info, ctrl| match info.caller_params.get(0) {
            Some(Value::String(s)) => {
                for (i, line) in s.lines().enumerate() {
                    ctrl.set(format!("$.line.{}", i), line, &info);
                }
                ctrl.set("$.line", s.lines().count(), &info);
            }

            Some(param) => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => param),
                    info.line()
                );
            }
            _ => {
                crate::error!(
                    "Unexpected {} values {:?} {}",
                    crate::color!(cyan => info.caller),
                    crate::color!(red => "None"),
                    info.line()
                );
            }
        });
    }
}
